Skip to content

fix: correct message id generation and base64 payload decoding - #697

Open
owenpearson wants to merge 2 commits into
uts/rest-payload-fixesfrom
uts/message-id-and-decoding
Open

owenpearson wants to merge 2 commits into
uts/rest-payload-fixesfrom
uts/message-id-and-decoding

Conversation

@owenpearson

@owenpearson owenpearson commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

PR 3 of 9 in the UTS REST unit stack. Base: uts/rest-payload-fixes.

Two small, independent fixes.

Message and annotation ids now use the URL-safe base64 alphabet. An id travels in a URL
path, where the standard alphabet's + and / are not safe to carry. RSL1k1 asks only for
"base64-encoding a sequence of at least 9 bytes" and names no alphabet, so both encodings
conform — but only one is safe in a path.

A message whose base64 payload cannot be decoded is now delivered rather than dropped.
base64.b64decode raises on a payload that is not valid base64, and the exception escaped
Message.from_encoded. RSL6b asks for the failure to be logged and the message delivered
with the encodings that were not applied, which is what the missing-cipher and
unsupported-encoding branches alongside it already do.

Review notes

The two commits touch disjoint files and can be reviewed independently. Worth noting that
the URL-safe change makes RSL1k2/message-id-format-0 and RSAN1c4/idempotent-id-generated-0
pass, but those specifications assert [A-Za-z0-9_-]+ against a features.md requirement
that names no alphabet — so they would reject a conforming SDK's ids at random. That is
recorded as a specification fault, not fixed here.

Verification

80 passed (test/unit); ruff check ably/ test/ clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability of idempotent publishing when generating annotation and message identifiers.
    • Invalid encoded message data is now handled without raising decoding errors, while preserving its original data and encoding.

@coderabbitai

coderabbitai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 270e7d39-3eec-49e7-9d10-fcc5bdd18f3b

📥 Commits

Reviewing files that changed from the base of the PR and between e47e873 and 81ed7b1.

📒 Files selected for processing (5)
  • ably/rest/annotations.py
  • ably/rest/channel.py
  • ably/types/mixins.py
  • test/ably/rest/restchannelpublish_test.py
  • test/unit/message_test.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 28c12ee6-bf7d-4ba8-a976-f781a72f32ab

📥 Commits

Reviewing files that changed from the base of the PR and between ad2efe3 and e47e873.

📒 Files selected for processing (5)
  • ably/rest/annotations.py
  • ably/rest/channel.py
  • ably/types/mixins.py
  • test/ably/rest/restchannelpublish_test.py
  • test/unit/message_test.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

Generated IDs for REST annotations and messages now use URL-safe Base64. Base64 decoding now handles decoding and encoding errors without propagating them, and a test checks that encoded message data remains unchanged.

Changes

Idempotent Publishing IDs

Layer / File(s) Summary
Generate and verify URL-safe IDs
ably/rest/annotations.py, ably/rest/channel.py, test/ably/rest/restchannelpublish_test.py
Generated annotation and message IDs use URL-safe Base64. The idempotency test decodes the generated base ID using URL-safe Base64.

Base64 Decoding Errors

Layer / File(s) Summary
Handle Base64 decoding errors
ably/types/mixins.py, test/unit/message_test.py
The decoder catches Base64 and Unicode encoding errors, logs the failure, and retains the encoding in the remaining list. A test checks that Message.from_encoded retains the input data and encoding.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: ttypic

Merge Risk: ⚪ Minimal · up to e47e8

The change uses URL-safe Base64 for generated IDs and preserves payloads when decoding raises. No concrete current-head failure is established; external-service acceptance of the URL-safe alphabet remains unverified, so normal integration checks are appropriate.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to e47e8

Keeping an undecodable message available to consumers is intentional, but that message can also become the decoding base for later messages. This could disrupt delivery on channels using delta decoding; no broader access or privilege change was established.

Retained concerns

  • Medium · security · inferred: A malformed Base64 message is delivered as opaque data but can also advance the realtime delta base and message ID. A following delta can therefore be processed against undecoded data rather than a successfully decoded predecessor.
Security review details

Security Blast Radius

  • inferred — The supported stateful impact is limited to a realtime channel's decoding context and messages subsequently decoded against it. No change to identity, authorization, or cross-service authority was established.

Security Findings and Attack Paths

  • inferred — If a received message has malformed Base64 and a later delta refers to it, the non-throwing failure can place the undecoded payload and its ID in the delta context. Whether a subsequent delta fails, recovers, or produces an unintended result depends on that later input and decoder.

Trust Boundaries and Controls

  • observed — Malformed payload data can now pass from protocol ingestion to a public message emitter, but the remaining encoding marks it as unapplied. The decoder already uses opaque delivery for unsupported encodings, and realtime handling starts recovery for a later delta failure reported with code 40018.

Resilience and Maintainability Implications

  • inferred — Exception-triggered rollback does not protect the context from this newly caught failure. The existing recovery path applies if a subsequent delta raises a recognized decode failure, rather than when the malformed Base64 message is delivered.

Hardening Proposals

  • proposed — Preserve opaque delivery while preventing a failed Base64 decode from becoming a valid delta predecessor; exercise a malformed message followed by a delta and replay against the same context.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes both primary changes: message ID generation and Base64 payload decoding.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the encoded stream,
URL-safe IDs hop into view.
If decoding stumbles on the way,
The data keeps its place in queue.
Soft paws review each change anew.

Comment @coderabbitai help to get the list of available commands.

@owenpearson
owenpearson force-pushed the uts/message-id-and-decoding branch from bcb3afc to 40895a2 Compare September 22, 2026 15:04
@owenpearson
owenpearson force-pushed the uts/message-id-and-decoding branch from 40895a2 to 30a7686 Compare September 23, 2026 08:48
@owenpearson
owenpearson force-pushed the uts/message-id-and-decoding branch from 30a7686 to 420379a Compare September 23, 2026 09:42
@owenpearson
owenpearson force-pushed the uts/message-id-and-decoding branch from 420379a to 61d4507 Compare September 23, 2026 13:47
@owenpearson
owenpearson force-pushed the uts/message-id-and-decoding branch from 61d4507 to 80151fe Compare September 23, 2026 14:01
@owenpearson
owenpearson added this pull request to stack #714 September 23, 2026 15:51
@owenpearson
owenpearson requested a review from ttypic September 23, 2026 15:52
@owenpearson
owenpearson force-pushed the uts/message-id-and-decoding branch from 80151fe to 05ff05f Compare September 23, 2026 17:20
@owenpearson
owenpearson force-pushed the uts/message-id-and-decoding branch from 05ff05f to e0abe60 Compare September 23, 2026 17:38
@ttypic
ttypic requested a review from VeskeR September 24, 2026 08:18

@ttypic ttypic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ttypic
ttypic removed the request for review from VeskeR September 24, 2026 08:20
owenpearson and others added 2 commits September 28, 2026 20:41
…habet

An id travels in a URL path, where the standard alphabet's `+` and `/` are
not safe to carry. RSL1k1 asks only for "base64-encoding a sequence of at
least 9 bytes" and names no alphabet, so both encodings conform.

`test_idempotent_library_generated` decodes a generated id, and needs the
matching decoder to do so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`base64.b64decode` raises on a payload that is not valid base64, and the
exception escaped `Message.from_encoded` rather than being reported. RSL6b
asks for the failure to be logged and the message delivered with the
encodings that were not applied, which is what the missing-cipher and
unsupported-encoding branches alongside it already do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
staging/pull/697/features — 81ed7b17 Deployed Sep 28, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants